home *** CD-ROM | disk | FTP | other *** search
- /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * NB: This file is used for both 16 and 32 bit code.
- * USE NO "int"s IN HERE!!!!
- *!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- *
- *
- * Crt0: C run-time initialization code.
- * Written by Eric R. Smith, and placed in the public domain.
- * Use at your own risk.
- *
- * _start(base): sets things up for the process whose basepage is
- * base. In particular, it sets up a valid environment, shrinks the
- * TPA to a reasonable value, and parses the command line.
- *
- * 01/03/89 ++jrb
- * The (new) meaning of _stksize: (thanks to allan pratt for the feedback)
- *
- * 11/27/91 ++jrb
- * More meanings for _stksize (thanks to eric and allan for the feedback)
- *
- * _stksize meaning
- * -4L keep 3/4, free 1/4, malloc from own heap
- * -3L keep 2/4 (1/2), free 1/2 malloc from own heap
- * -2L keep 1/4 of memory, free 3/4, malloc from own heap
- *
- * NOTE: all of the following will do malloc from Malloc() first.
- * when that fails, in the -1L case malloc() will then do further
- * mallocs from our own heap. This lets us use the maximum amount of
- * memory in traditional ST's as well as in newer split address
- * STs. In the >=0 cases futher malloc()'s will fail, and they
- * will not try to malloc() from own heap. Out own space in the >= 0
- * cases are intended mainly for stack+alloca()'s.
- *
- * -1L keep all of memory (except MINFREE at top) and do
- * mallocs from own heap, with heap grown upwards towards
- * stack, and the stack growing down towards heap,
- * with a minimum slush between them so that they
- * dont meet (only checked while malloc'ing). With
- * this model, further spawning is not possible, but it is
- * well suited for programs such as gcc-cc1 etc.
- * Thanks to Piet van Oostrum & Atze Dijkstra for this idea
- *
- * 0L keep minimum amount of memory. this is also the
- * case when _stksize is undefined by the user.
- * 1L keep 1/4 of memory, free 3/4 ( as in Alcyon GEMSTART)
- * 2L keep 2/4 (1/2), free rest
- * 3L keep 3/4, free 1/4
- * other keep that many bytes
- * -other keep |other| bytes and malloc from own heap
- *
- * 02/14/90 ++jrb (thanks edgar)
- * auto acc detect
- * undump friendly
- * Note: some of the stuff here may seem extraneous: these are in
- * prep for upcoming plug'n play device interface
- * (the moment the ol'boss lets me do some "real" work).
- *
- *
- * NOTE: dumping applications should use _initial_stack instead: if
- * !=0, then _stksize is initialized from _initial_stack, and
- * mallocs are always from internal heap. (TeX works much better now),
- * thanks edgar!
- *
- * Acc convention:
- * user sets _heapbase to bottom of stack + heap area
- * sets _stksize to the size of this area
- * at startup, sp will be set to top of this area
- * (_heapbase + _stksize ) and malloc()'s will happen from heap.
- * (note malloc() and *not* Malloc())
- * OR
- * user sets only _stksize. then _heapbase is set to Malloc(_stksize)
- * sp to _heapbase + _stksize and mallocs all happen from this heap.
- *
- * 02/16/90 ++jrb
- * - bug fix: dont get screwed by desktop launch when fast bit is set
- * convert env string to format usable
- * (atari get your act together!!)
- */
-
- #include <basepage.h>
- #include <osbind.h>
- #ifndef _COMPILER_H
- #include <compiler.h>
- #endif
- #include <stddef.h>
-
- #define isspace(c) ((c) == ' '||(c) == '\t')
- #define BUFSIZ ((unsigned long)1024) /* this must track the value */
- /* in stdio.h */
- #define MINFREE (8L * 1024L) /* free atleast this much mem */
- /* on top */
- #define MINKEEP (8L * 1024L) /* keep atleast this much mem */
-
- /*
- * this little goodie is for emacs
- * edgar: note: it has grown two leading '_',
- * adjust in emacs/src/sysdep.c:start_of_data()
- *
- * __data_start removed, as that can be determined from the basepage.
- */
-
- BASEPAGE *_base;
- char **environ;
- static long argc;
- static char **argv;
-
- /*
- * initial stack is used primarily by dumping application,
- * if it is, malloc is always from heap, and _stksize is init
- * from initial_stack (to preserve the value in the undumped run)
- */
- long _initial_stack; /* .comm __initial_size, 4 */
- extern long _stksize; /* picked up from user or stksiz.c */
- /* set to heap base addr when (_stksize <= -1L) || _initial_stack || When DA */
- void *_heapbase;
-
- /* default sizeof stdio buffers */
- size_t __DEFAULT_BUFSIZ__; /* .comm */
-
- /* are we an app? */
- short _app;
-
- /* are we on a split addr mem ST */
- short _split_mem = 0;
-
- /* externs to pull in ident strings of all used libraries into the
- executable. if a library is not used, then the extern is satisfied
- by a dummy in the library
- */
- asm("
- .globl ___Ident_libg
- .globl ___Ident_curses
- .globl ___Ident_widget
- .globl ___Ident_gem
- .globl ___Ident_pml
- .globl ___Ident_gnulib
- ");
-
- static void _acc_main __PROTO((void));
- static void _start1 __PROTO((BASEPAGE *bp));
- static long parseargs __PROTO((BASEPAGE *bp));
- static void setup_handlers __PROTO((void));
- static void _start0 __PROTO((BASEPAGE *));
- static void setup_handlers __PROTO((void));
- __EXTERN void _main __PROTO((long, char **, char **));
- __EXTERN void _init_signal __PROTO((void));
- __EXTERN void _start __PROTO((BASEPAGE *));
- #ifdef __GCRT0__
- __EXTERN void monstartup __PROTO((void *lowpc, void *highpc));
- __EXTERN void monitor __PROTO((void *lowpc, void *highpc, void *buffer, unsigned long bufsize, unsigned int nfunc));
- __EXTERN void moncontrol __PROTO((long flag));
- __EXTERN void _mcleanup __PROTO((void));
- __EXTERN int profil __PROTO((void *buff, unsigned long bufsiz, unsigned long offset, int shift));
- #endif
-
- /*
- * From: kbad@atari.UUCP (Ken Badertscher)
- * Newsgroups: comp.sys.atari.st
- * Subject: Am I a DA? (long)
- * .....
- * I mentioned before that a DA's registers are garbage on startup, well,
- * that's not entirely true. When the DA gets control, register A0 always
- * points to its basepage. When a program is started by a GEMDOS Pexec(),
- * register A0 is always cleared. Using this fact, it is possible to
- * implement startup code which gets the basepage address from register A0
- * if the code is launched as a DA, or at 4(sp) if the code is launched by
- * Pexec(). Since it knows how it was launched, it can also do the stack
- * setup required of a DA, otherwise it can use the stack pointer it gets.
- *
- */
- /*
- * revert back to testing A0 (instead of SP) after controversy on the net.
- * packers will just have to fix themselves.
- * in addition to testing A0 check long A0@(36) (parents basepage). for an
- * acc this should be NULL.
- */
- __asm__("
- .text
- .even
- .globl __start
- __start:
- "
- #ifdef __MBASE__
- " movl a0,a1 /* Find basepage, data seg */
- cmpw #0,a1
- jne 1f
- movl sp@(4),a1
- 1:
- movl a1@(16)," __MBASESTR__ " /* Set base to data seg + 32K */
- subw #32768," __MBASESTR__ "
-
- "
- #define Base __MBASESTR__ "@(__base)"
- #define Heapbase __MBASESTR__ "@(__heapbase)"
- #define Stksize __MBASESTR__ "@(__stksize)"
- #else
- #define Base "__base"
- #define Heapbase "__heapbase"
- #define Stksize "__stksize"
- #endif
- " cmpw #0,a0 /* test acc or prog */
- jeq __start0 /* br if prog */
- tstl a0@(36) /* tst parent basepage pointer */
- jne __start0 /* its a prog if != 0 */
-
- /* its an acc, set up a stck+heap */
- movl a0," Base " /* sto basepage */
- tstl " Heapbase " /* setup _heapbase and sp */
- jne 1f
- movl " Stksize ",d3 /* _heapbase not specified */
- addql #3, d3
- andl #0xfffffffc,d3
- movl d3,sp@- /* _heapbase = Malloc(_stksize) */
- movw #0x48,sp@-
- trap #1
- addqw #6,sp
- movl d0," Heapbase "
- addl d3,d0
- movl d0, sp /* sp = _heapbase + _stksize */
- jra __acc_main
- 1: /* heap base specified */
- movl " Heapbase ",sp /* setup sp */
- addl " Stksize ",sp
- jra __acc_main
- .data"); /* acc main */
- /* dont even think of */
- /* dropping through */
-
- static char *acc_argv[] = {"", (char *) 0}; /* no name and no arguments */
-
- static void _acc_main(void)
- {
- _app = 0; /* this is an accessory */
- _main(1L, acc_argv, acc_argv);
- /*NOTREACHED*/
- }
-
- void _start0(bp) /* bp is passed at sp@(4) */
- register BASEPAGE *bp;
- {
- /* temporarily set sp at hitpa (rounded),then call the real
- startup function. not doing this was blowing up the
- stack provided by gemdos on a 1040, because _start1()
- was pushing too many reggies on the stack
- _start1() will finally set sp to its final value and
- then do a mshrink().
- */
- asm volatile("movl %0,sp" ::"r"((long)bp->p_hitpa & ~3L));
- _start1(bp);
- }
-
- static void _start1(bp)
- register BASEPAGE *bp __asm("a3");
- {
- register long m __asm("d3");
- register long freemem __asm("d4");
- extern void etext(); /* fake-out if pcrel used */
-
- _app = 1; /* its an application */
- _base = bp;
- if(!__DEFAULT_BUFSIZ__)
- __DEFAULT_BUFSIZ__ = BUFSIZ;
-
- m = parseargs(bp); /* m = # bytes used by environment + args */
- /* make m the total number of bytes required by program sans stack/heap */
- m += (bp->p_tlen + bp->p_dlen + bp->p_blen + sizeof(BASEPAGE));
- m = (m + 3L) & (~3L);
- /* freemem the amount of free mem accounting for MINFREE at top */
- if((freemem = (long)bp->p_hitpa - (long)bp - MINFREE - m) <= 0L)
- goto notenough;
-
- if(_initial_stack)
- {
- /* the primary use of _initial_stack will be in dumping */
- /* applications where only a heap for malloc makes sense */
- _heapbase = (void *) ((long)bp + m);
- _stksize = _initial_stack;
- }
-
- if((_stksize < -1L))
- {
- _heapbase = (void *) ((long)bp + m);
- _stksize = -_stksize - 1;
- }
-
- if((!_initial_stack) && (_stksize >= -1L))
- { /* malloc from Malloc first, then from own heap */
- _split_mem = 1;
- }
-
- switch(_stksize)
- {
- case -1L: /* keep all but MINFREE */
- _stksize = freemem;
- _heapbase = (void *) ((long)bp + m);
- break;
-
- case 0L: /* free all but MINKEEP */
- _stksize = MINKEEP;
- break;
-
- case 1L: /* keep 1/4, free 3/4 */
- _stksize = freemem >> 2;
- break;
-
- case 2L: /* keep 1/2, free 1/2 */
- _stksize = freemem >> 1;
- break;
-
- case 3L: /* keep 3/4, free 1/4 */
- _stksize = freemem - (freemem >> 2);
- break;
-
- default:
- /* if _stksize > 0, keep that much */
- break;
- }
-
- /* make m the total number of bytes including stack */
- _stksize = _stksize & (~3L);
- m += _stksize;
-
- /* make sure there's enough room for the stack */
- if (((long)bp + m) > ((long)bp->p_hitpa - MINFREE))
- goto notenough;
-
- /* set up the new stack to bp + m */
- asm volatile("\
- movl %0, sp | move base to sp
- addal %1, sp | add total bytes"
- : /* outputs */
- : "g"(bp), "g"(m) /* inputs */
- ); /* we dont tell gcc about clobbered reggies */
-
- /* shrink the TPA - this is always correct, shared text or not -- hyc */
- (void)Mshrink(bp, m);
- asm volatile("subl a6,a6"); /* clear link reg for gdb */
-
- /* establish handlers, call the main routine */
- setup_handlers();
- #ifdef __GCRT0__
- monstartup((void *)(bp->p_tbase), (void *)etext-1);
- #endif
- _main(argc, argv, environ);
- /* not reached normally */
-
- notenough:
- Cconws("Fatal error: insufficient memory\r\n");
- Pterm(-1);
- }
-
-
- /*
- * parseargs(bp): parse the environment and arguments pointed to by the
- * basepage. Return the number of bytes of environment and arguments
- * that have been appended to the bss area (the environ and argv arrays
- * are put here, as is a temporary buffer for the command line, if
- * necessary).
- *
- * The MWC extended argument passing scheme is assumed.
- *
- */
-
- static long parseargs(bp)
- BASEPAGE *bp;
- {
- long count = 4; /* compensate for aligning */
- long i;
- char *from, *cmdln, *to;
- char **envp, **arg;
-
- /* handle the environment first */
-
- environ = envp = (char **)(( (long)bp->p_bbase + bp->p_blen + 4) & (~3));
- from = bp->p_env;
- while (*from) {
-
- /* if we find MWC arguments, tie off environment here */
- if (*from == 'A' && *(from+1) == 'R' && *(from+2) == 'G' &&
- *(from+3) == 'V' && *(from+4) == '=') {
- *envp++ = (char *) 0; count += 4;
- *from++ = 0;
- #ifdef STRICTLY_COMPATIBLE_WITH_STANDARD
- if (bp->p_cmdlin[0] != 127)
- goto old_cmdlin;
- #endif
- while (*from++) ; /* skip ARGV= string */
- argv = arg = envp++;
- *arg++ = from; count+= 4;
- while (*from++) ; /* skip argv[0] */
- goto do_argc;
- }
- *envp++ = from;
- count += 4;
- while (*from++);
-
- /* if launched from desktop -- fix up env
- * be careful while doing this, as the environment
- * may have a variable whose value is the empty
- * string. (make puts a MAKFLAGS=\0). The desktop
- * typically has "PATH=\0C:\\0\0", so to distinguish
- * the two cases, check for uppercase drive letter
- * followed by ":\\"
- */
- #define ISDRV(x) (('A' <= (x)) && ((x) <= 'Z'))
- if ( (from[ -2 ] == '=') && (ISDRV(*from)) &&
- (from[1] == ':') && (from[2] == '\\') )
- {
- char *p = &from[-1]; /* typically "PATH=\0C:\\0\0" */
- while(*from)
- *p++ = *from++;
- *p = '\0'; from++;
- }
- }
- *envp++ = (char *)0;
- count += 4;
-
- /* Allocate some room for the command line to be parsed */
- cmdln = bp->p_cmdlin;
- i = *cmdln++;
- from = to = (char *) envp;
- if (i > 0) {
- count += (i&(~3));
- envp = (char **) ( ((long) envp) + (i&(~3)) );
- }
- envp += 2; count += 8;
-
- /* Now parse the command line and put argv after the environment */
-
- argv = arg = envp;
- *arg++ = ""; /* argv[0] not available */
- count += 4;
- while(i > 0 && isspace(*cmdln) )
- cmdln++,--i;
-
- while (i > 0) {
- if (isspace(*cmdln)) {
- --i; cmdln++;
- while (i > 0 && isspace(*cmdln))
- --i,cmdln++;
- *to++ = 0;
- }
- else {
- if (!(*to++ = *cmdln++)) break;
- --i;
- }
- }
- *to++ = '\0';
- *to = '\0'; /* bug fix example:cmdln == '\3' 'a' ' ' 'b' '\0' */
- /* the loop below expects \0\0 at end to terminate! */
- /* the byte @ cmdln[i+2] != 0 when fast bit is set */
- do_argc:
- argc = 1; /* at this point argv[0] is done */
- while (*from) {
- *arg++ = from;
- argc++;
- count += 4;
- while(*from++) ;
- }
- *arg++ = (char *) 0;
- return count+4;
- }
-
- static void setup_handlers(void)
- {
- /* more stuff to come */
- _init_signal();
- }
-
- void __exit(status)
- long status;
- {
- #ifdef __GCRT0__
- moncontrol(0L);
- _mcleanup();
- #endif
- Pterm(status);
-
- }
-